home *** CD-ROM | disk | FTP | other *** search
/ PC World 2008 September / PCWorld_2008-09_cd.bin / v cisle / sadanastroju / interclue-1.5.6-fx.xpi / chrome / interclue / content / interclue.js < prev    next >
Text File  |  2008-06-17  |  39KB  |  1,180 lines

  1.  
  2. var interclue = window.interclue || {};
  3.  
  4. interclue.GUID = '{c33c5b47-69c8-45a4-a5e0-af85bbe628dd}';
  5.  
  6. interclue.isSiteHound = false;
  7.  
  8. interclue.isProfileDir = true;
  9.  
  10. interclue.servers = [];
  11.  
  12. interclue.servers.push({
  13.     'name' : 'live',
  14.     'url' : 'https://interclue.com',
  15.     'icon' : 'chrome://interclue/skin/buttons/server.live.png'});
  16.  
  17. interclue.servers.push({
  18.     'name' : 'local',
  19.     'url' : 'http://localhost/interclue',
  20.     'icon' : 'chrome://interclue/skin/buttons/server.local.png'});
  21.     
  22. interclue.servers.push({
  23.     'name' : 'dev',
  24.     'url' : 'http://dev.izeal.com/interclue.tabbed',
  25.     'icon' : 'chrome://interclue/skin/buttons/server.dev.png'});
  26.     
  27.  
  28. interclue.nextCall = '';
  29.  
  30.  
  31. interclue.fixNoScript = function(url, enable){
  32.     if (window.noscriptUtil){
  33.  
  34.         var ns = window.noscriptUtil.service;
  35.  
  36.         if (ns && ns.setJSEnabled){
  37.             ns.setJSEnabled(url, enable);
  38.         }
  39.     }
  40. }
  41.  
  42.  
  43. interclue.registerStylesheet = function(href){
  44.     //This code is from Conlan Wesson Link Alert v0.2
  45.     //who got it from Raphael Jolivet's smart-cursor v0.2
  46.  
  47.     // Get Style Sheet service
  48.     var sss = Components.classes["@mozilla.org/content/style-sheet-service;1"].getService(Components.interfaces.nsIStyleSheetService);
  49.     // Get IO service
  50.     var ios = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
  51.     // Build URI
  52.     var uri = ios.newURI(href, null, null);
  53.     // Register sheet
  54.     sss.loadAndRegisterSheet(uri, sss.USER_SHEET);
  55. }
  56.  
  57. interclue.unregisterStylesheet = function(href){
  58.     var sss = Components.classes["@mozilla.org/content/style-sheet-service;1"].getService(Components.interfaces.nsIStyleSheetService);
  59.     var ios = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
  60.     var uri = ios.newURI(href, null, null);
  61.     sss.unregisterSheet(uri, sss.USER_SHEET);
  62. }
  63.  
  64. interclue.inArray = function(needle, haystack){
  65.     for (var i=0; i<haystack.length; i++){
  66.         if (haystack[i] == needle){
  67.             return true;
  68.         }
  69.     }
  70.     return false;
  71. }
  72.  
  73. /**
  74. * load our scripts into the iframe
  75. */
  76. interclue.initClueBridge = function(){
  77.  
  78.     if (!interclue.inArray("platform-firefox.js", interclue.scripts)){
  79.         interclue.scripts.push("platform-firefox.js");
  80.     }
  81.     
  82.     //scripts must be loaded using a file:// path 
  83.     
  84.     // SiteHound installs Interclue into the Browser/extensions directory.
  85.     // however we install to the user's extension dir.
  86.     var dirGetId = (interclue.isSiteHound) ? "CurProcD" : "ProfD";
  87.     
  88.     //however I like to keep sitehound away from my install directory.
  89.     if (interclue.isProfileDir){
  90.         dirGetId = "ProfD";
  91.     }
  92.     
  93.     var dir = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties).get(dirGetId, Components.interfaces.nsILocalFile).path;
  94.     var doc = document.getElementById('interclue-iframe').contentWindow.document;
  95.     var fileUrl = "file:///"+ dir.replace(/\\\//g, '/') +"/extensions/" + interclue.GUID +"/chrome/interclue/content/cluecore/";
  96.     
  97.     interclue.fixNoScript('file:', true);
  98.  
  99.     for (var i=0; i<interclue.scripts.length; i++){
  100.         interclue.addScript(fileUrl + interclue.scripts[i], doc);
  101.     }
  102.     
  103.     interclue.fixNoScript('file:', false);
  104.     
  105.     interclue.initKlib();
  106. }
  107.  
  108. /**
  109. */
  110. interclue.addScript = function(src, doc){
  111.     doc = doc || document;
  112.     var script = doc.createElement('script');
  113.     script.src = src;
  114.     script.type = 'text/javascript';
  115.     try {
  116.         doc.getElementsByTagName('head')[0].appendChild(script);
  117.     }catch(e){
  118.         doc.body.appendChild(script);
  119.     }
  120. }
  121.  
  122.  
  123. interclue.initKlib = function(){
  124.     var win = document.getElementById('interclue-iframe').contentWindow;
  125.  
  126.     if (win && win.Klib && win.Klib.init){
  127.         
  128.         win.Klib.init();
  129.         
  130.         if (interclue.nextCall){
  131.             var code = interclue.nextCall;
  132.             interclue.nextCall = '';
  133.             
  134.             var Klib = interclue.getKlib();
  135.             eval(code);
  136.         }
  137.         //show ready image?
  138.         win.Klib.Toolbar.refresh();
  139.     }
  140.     else {
  141.         setTimeout(interclue.initKlib, 100);
  142.     }
  143. }
  144.  
  145.  
  146. /**
  147. */
  148. interclue.call = function(code, event){
  149.  
  150.     //only activate on left click
  151.  
  152.     if (event && event.button == 2){return};
  153.  
  154.     var Klib = interclue.getKlib();
  155.     
  156.     if (Klib){
  157.         eval(code);
  158.     }
  159.     else {
  160.         interclue.nextCall = code;
  161.         interclue.initClueBridge();
  162.     }
  163. }
  164.  
  165.  
  166. interclue.getKlib = function(){
  167.     var iframe = document.getElementById('interclue-iframe');
  168.     
  169.     if (iframe && iframe.contentWindow && iframe.contentWindow.Klib && iframe.contentWindow.Klib.initalized){
  170.         return iframe.contentWindow.Klib;
  171.     }
  172.     else {
  173.         return null;
  174.     }
  175. }
  176.  
  177.  
  178.  
  179. interclue.handleClose = function(){
  180.     var Klib = interclue.getKlib();
  181.     
  182.     if (Klib){
  183.         Klib.GEvent.fireLocal('windowclose');
  184.     }
  185.     
  186.     gBrowser.removeEventListener("DOMContentLoaded", interclue.onBrowerDOMContentLoaded, false);
  187.     window.removeEventListener('close', interclue.handleClose, true);
  188.     window.removeEventListener('mousemove', interclue.handleMouseMove, true);
  189.     interclue.Mouse.cleanup();
  190. }
  191.  
  192. interclue.initalized = false;
  193.  
  194. interclue.init = function(){  
  195.  
  196.     if (gBrowser && !interclue.initalized){
  197.         interclue.initalized = true;
  198.         window.removeEventListener('load', interclue.init, true);
  199.         
  200.         interclue.setFirefoxVersionInfo();
  201.         //no longer used, statusbar button only.
  202.         //interclue.showToolbarButton('interclue-login-toolbarbutton');
  203.         //interclue.showToolbarButton('interclue-logout-toolbarbutton', 'interclue-login-toolbarbutton');
  204.         
  205.         interclue.Mouse.init();
  206.         interclue.Tooltip.init();
  207.         
  208.         gBrowser.addEventListener("DOMContentLoaded", interclue.onBrowerDOMContentLoaded, false);
  209.         
  210.         window.addEventListener('close', interclue.handleClose, true);
  211.         //window.addEventListener('keydown', interclue.handleKeyDown, true);
  212.         //window.addEventListener('keyup', interclue.handleKeyUp, true);
  213.         //window.addEventListener('blur', interclue.handleKeyUp, true);
  214.         
  215.         window.addEventListener('mousemove', interclue.handleMouseMove, true);
  216.         
  217.         //prevent printing of clueframes/linkscents        
  218.         interclue.registerStylesheet('chrome://interclue/content/linkscents.css');
  219.         
  220.         //cleanup unused preferences
  221.         interclue.killPref("alltheclues");
  222.         
  223.         interclue.uninstallObserver.register();
  224.         interclue.addEvent("uninstall-request", interclue.handleUninstallRequest);
  225.         interclue.addEvent("uninstall-cancel", interclue.handleUninstallCancel);
  226.         
  227.         if (interclue.getPref("interclue.resetPrefs") === true){
  228.             interclue.setPref("interclue.resetPrefs", false);
  229.             interclue.setPref("interclue.preferences", '');
  230.         }
  231.         
  232.         interclue.checkIfUpdated();
  233.         
  234.         //lets wait a moment and then do it
  235.         //adding delay due to unknown browser crash at startup.
  236.         //dont know why it's happening, but this appears to fix it.
  237.         setTimeout(function(){
  238.             document.getElementById('interclue-iframe').setAttribute('src', "chrome://interclue/content/cluecore/interclue.html");
  239.         }, 2000);
  240.         
  241.         //send update ping 2 minutes after browser start
  242.         interclue.updatePingTimer = setTimeout(interclue.updatePing, 2 * 60 * 1000);
  243.         
  244.         setTimeout(interclue.addAdblockExceptionRules, 2000);
  245.     }
  246. }
  247.  
  248.  
  249. /**
  250. * set firefox version info
  251. */
  252. interclue.setFirefoxVersionInfo = function(){
  253.     var verStr = interclue.getPref("extensions.lastAppVersion");
  254.     if (verStr){
  255.         var version = verStr.split(/\./g);
  256.         interclue.FFVersion = {};
  257.         interclue.FFVersion.major = parseInt(version[0]);
  258.         interclue.FFVersion.minor = version[1] ? parseInt(version[1]) : 0;
  259.         interclue.isFF2 = (interclue.FFVersion.major == 2);
  260.         interclue.isFF3 = (interclue.FFVersion.major == 3);
  261.     }
  262. }
  263. /**
  264. * handle DOM loaded event
  265. */
  266. interclue.onBrowerDOMContentLoaded = function(evt){
  267.     //get the right document
  268.     var doc = evt.originalTarget;
  269.     
  270.     if (doc && doc instanceof HTMLDocument){
  271.         //good to go
  272.         if (interclue.getPref("interclue.checkForEvilLinks", false)){
  273.             interclue.checkPageForEvilLinks(doc);
  274.         }
  275.     }
  276. }
  277.  
  278. /**
  279. * inserts icons next to evil links on a page 
  280. */
  281. interclue.checkPageForEvilLinks = function(doc){    
  282.     var links = doc.getElementsByTagName("a");
  283.     for (var i=0; i<links.length; i++){
  284.         //need to send this to a separate function so the callback works correctly
  285.         interclue.checkIfEvilLink(links[i]);     
  286.     }
  287. }
  288.  
  289. /**
  290. * inserts an icon next to a link if it is evil
  291. */
  292. interclue.checkIfEvilLink = function(link){
  293.  
  294.     var url = interclue.removeRedirects(link.href);
  295.  
  296.     //dont check invalid urls
  297.     if (!interclue.urlToURI(url)){return}
  298.     
  299.     //or internal links
  300.     if (interclue.isInternalLink(link)){return}
  301.     
  302.     interclue.isEvilURL(url, function(url, response){
  303.     
  304.         //make sure the link still exists.
  305.         if (!link){return}
  306.         
  307.         var tables = (response) ? response.split(/\s*\,\s*/g) : [];
  308.         for (var i=0; i<tables.length; i++){
  309.             switch(tables[i]){
  310.                 case "goog-malware-shavar":
  311.                     //is malware site.
  312.                     //better mark this lin as evil.
  313.                     link.setAttribute('interclue_link_type', 'malware');
  314.                     //interclue.insertIcon(link, "chrome://interclue/skin/warning-malware.png", "WARNING: visiting this web site may harm your computer!");
  315.                     break;
  316.                     
  317.                 case "goog-phish-shavar":
  318.                     //is phishing site
  319.                     link.setAttribute('interclue_link_type', 'phish');
  320.                     //interclue.insertIcon(link, "chrome://interclue/skin/warning-phishing.png", "WARNING: this site is thought to be a phishing (web forgery) scam");
  321.                     break;
  322.                 
  323.                 case "":
  324.                 case null:
  325.                     //link is safe
  326.                     break;
  327.                     
  328.                 default:
  329.                     //unknown table name, assume it's evil.
  330.                     interclue.logError(Error("Interclue: Unknown table name: ["+ response +"]"));
  331.             }
  332.         }
  333.     })
  334. }
  335.  
  336. /**
  337. * inserts an icon directly after a link
  338. */
  339. interclue.insertIcon = function(link, iconUrl, tooltip){
  340.     var doc = link.ownerDocument;
  341.     var img = doc.createElement("img");
  342.     img.setAttribute("src", iconUrl);
  343.     if (title){
  344.         img.setAttribute("title", tooltip);
  345.     }
  346.     img.setAttribute("align", "bottom");
  347.     img.setAttribute("border", "0");
  348.     
  349.     //we'll need to find this link if a user hovers over the icon.
  350.     //img.link //doesn't work
  351.     //just setting the same href will not work (their might be more than one link with the same url)
  352.     img.setAttribute("interclue_link_href", link.href);
  353.     var links = doc.getElementsByTagName('a');
  354.     for (var i=0; i<links.length; i++){
  355.         if (links[i] === link){
  356.             img.setAttribute("interclue_link_index", i);
  357.             break;
  358.         }
  359.     }
  360.     
  361.     //need to tell the linkscent positioner to adjust the linkscents position next to our image.
  362.     link.setAttribute("interclue_linkclue_offset_x", "18");
  363.     
  364.     interclue.insertAfter(img, link);
  365. }
  366.  
  367. /**
  368. * inserts an element directly after another element in a DOM
  369. */
  370. interclue.insertAfter = function(eleToInsert, ele){
  371.     if (ele.nextSibling){
  372.         ele.parentNode.insertBefore(eleToInsert, ele.nextSibling);
  373.     }
  374.     else {
  375.         ele.parentNode.appendChild(eleToInsert);
  376.     }
  377. }
  378.  
  379. /**
  380. * calls callback with 2 args, 1st arg is the url that as passed.
  381. * 2nd arg is a comma separated string of tables to which the url belongs
  382. * if url not found in any tables 2nd arg will be an empty string
  383. * if url is invalid 2nd arg will be null.
  384. */
  385. interclue.isEvilURL = function(url, callback){
  386.     //check url, invalid urls (or urls with other protocols) will throw an error 
  387.     //in FF2 phishWarden.isEvilURL().
  388.     if (/^http(s)?:/i.test(url) && interclue.urlToURI(url)){
  389.          
  390.         //firefox 2 uses a safbrowsing object
  391.         if (interclue.isFF2 && interclue.getPref("browser.safebrowsing.enabled", true) && !interclue.getPref("browser.safebrowsing.remoteLookups", false)){
  392.          
  393.             //firefox 2 uses a safebrowsing object to lookup urls
  394.             //the safebrowsing.phishWarden is not enabled immediatly so we need to check if it's ready and active
  395.             if (top.safebrowsing && top.safebrowsing.phishWarden && top.safebrowsing.phishWarden.isEvilURL){
  396.                 try {    
  397.                     top.safebrowsing.phishWarden.isEvilURL(url, function(arg){
  398.                         var IN_BLACKLIST = 0;
  399.                         var IN_WHITELIST = 1;
  400.                         var NOT_FOUND = 2;
  401.                         //if found in blacklist AND whitelist then IN_WHITELIST will be returned
  402.                         if (arg == IN_BLACKLIST){
  403.                             //convert to FF3 is phishy info
  404.                             callback(url, "goog-phish-shavar");
  405.                         }
  406.                         else {
  407.                             callback(url, "");
  408.                         }
  409.                     });
  410.                     return;
  411.                 }catch(e){}
  412.             }
  413.         }
  414.         //firefox 3 uses something else
  415.         else if (interclue.isFF3){
  416.             var uri = interclue.urlToURI(url);
  417.             if (uri && uri.spec && /^http(s)?:/.test(uri.spec)){
  418.                 //some urls (javascript: ) will throw a error if we try the lookup() on them.
  419.                 try {
  420.                     var nsIUrlClass = Components.classes["@mozilla.org/url-classifier/dbservice;1"]
  421.                         .getService(Components.interfaces.nsIUrlClassifierDBService);
  422.                     nsIUrlClass.lookup(uri.spec, function(response){
  423.                         callback(url, response);
  424.                     });
  425.                     return;
  426.                     
  427.                 }catch(e){
  428.                     //invalid URI?
  429.                     interclue.logError(e);
  430.                 }
  431.             }
  432.         }
  433.     }
  434.     //if we get here something has gone wrong
  435.     callback(url, null);
  436. }
  437.  
  438.  
  439.  
  440. /**
  441. * log an error to the error console
  442. */
  443. interclue.logError = function(err){
  444.     Components.utils.reportError(err); 
  445. }
  446.  
  447. /**
  448. * logs a message to the error console
  449. */
  450. interclue.logMsg = function(msg){
  451.     var str = "";
  452.     for (var i=0; i<arguments.length; i++){
  453.         str += arguments[i] + "\n";
  454.     }
  455.     
  456.     var consoleService = Components.classes["@mozilla.org/consoleservice;1"]
  457.         .getService(Components.interfaces.nsIConsoleService);
  458.     consoleService.logStringMessage("interclue:\n" + str);
  459. }
  460.  
  461. interclue.addAdblockExceptionRules = function(){
  462.     
  463.     //adblockplus (easylist subscription) rightly blocks amazon affiliate adds.
  464.     //but our summary of this type of link uses the amazon api to display info about the amazon product
  465.     //by adding a unique string (interclue=1) to the api url and 
  466.     //adding an exception rule we can display our summaries whilst still prevent normal adds from
  467.     //being displayed.
  468.     if (typeof abpTogglePattern == "function"){
  469.         abpTogglePattern("@@http://rcm.amazon.com/e/cm?interclue*", true);     
  470.         abpTogglePattern("@@http://rcm-images.amazon.com/images/*", true);     
  471.     }
  472. }
  473.  
  474. interclue.shutdown = function(evt){
  475.     try {
  476.         clearTimeout(interclue.updatePingTimer);
  477.     }catch(e){}
  478.     
  479.     
  480.     if (interclue.uninstallOnNextStart){
  481.         //remove prefs on uninstall
  482.         interclue.killPref("interclue");
  483.         interclue.savePrefFile();
  484.     }
  485. }
  486.  
  487. interclue.savePrefFile = function(){
  488.     var prefService = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
  489.     prefService.savePrefFile(null);
  490. }
  491.  
  492. /**
  493. * Flag to indicate if interclue will be uninstalled on browser restart 
  494. */
  495. interclue.uninstallOnNextStart = false;
  496.  
  497. interclue.handleUninstallRequest = function(){
  498.  
  499.     //set a flag to indicate that interclue will be uninstalled
  500.     interclue.uninstallOnNextStart = true;
  501.     
  502.     //open the nag url.
  503.     var Klib = interclue.getKlib();
  504.     
  505.     if (Klib){
  506.         var url = "http://interclue.com/uninstall.html"
  507.         
  508.         url = Klib.Url.add(url, "build", Klib.App.build);
  509.         url = Klib.Url.add(url, "guid", Klib.User.getGuid());
  510.         
  511.         Klib.ClueBridge.openUrl(url, true, true, true);
  512.     }
  513. }
  514.  
  515.  
  516. interclue.handleUninstallCancel = function(){
  517.     interclue.uninstallOnNextStart = false;
  518. }
  519.  
  520.  
  521. //ref: http://xulsolutions.blogspot.com/2006/07/creating-uninstall-script-for.html
  522. interclue.uninstallObserver = {
  523.     
  524.     //flag to tell if item is to be uninstalled at next restart.
  525.     _uninstall : false,
  526.     
  527.     //handle observe event
  528.     observe : function(subject, topic, data) {
  529.         //action called
  530.         if (topic == "em-action-requested") {
  531.             subject.QueryInterface(Components.interfaces.nsIUpdateItem);
  532.  
  533.             if (subject.id == interclue.GUID) {
  534.                 //add-on being marked for uninstall
  535.                 if (data == "item-uninstalled") {
  536.                     this._uninstall = true;
  537.                     interclue.fireEvent("uninstall-request");
  538.                 } 
  539.                 //cancel uninstall
  540.                 else if (data == "item-cancel-action") {
  541.                     this._uninstall = false;
  542.                     interclue.fireEvent("uninstall-cancel");
  543.                 }
  544.             }
  545.         } 
  546.         //browser is closing
  547.         else if (topic == "quit-application-granted") {
  548.             if (this._uninstall) {
  549.                 /* uninstall stuff. */
  550.                 interclue.fireEvent("uninstall");
  551.             }
  552.             this.unregister();
  553.         }
  554.     },
  555.     
  556.     //start observing
  557.     register : function() {
  558.         var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
  559.         observerService.addObserver(this, "em-action-requested", false);
  560.         observerService.addObserver(this, "quit-application-granted", false);
  561.     },
  562.     
  563.     //stop observing
  564.     unregister : function() {
  565.         var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
  566.         observerService.removeObserver(this,"em-action-requested");
  567.         observerService.removeObserver(this,"quit-application-granted");
  568.     }
  569. }
  570.  
  571. interclue.handleMouseMove = function(evt){
  572.     //set a flag to say if the mouse currently over an html document.
  573.     var t = evt.target;
  574.     
  575.     interclue.isMouseOverHTMLDoc = (t && t.nodeName && t.getAttribute && t.nodeName == 'tabbrowser' && t.getAttribute('id') == 'content');
  576. }
  577.  
  578.  
  579. interclue.showToolbarButton = function(id, insertAfter){
  580.  
  581.     var navbar = document.getElementById('nav-bar');
  582.     var buttons = (navbar.currentSet) ? navbar.currentSet : navbar.defaultSet;
  583.  
  584.     if (buttons.indexOf(id) == -1){
  585.  
  586.         var set = buttons.split(/\s*,\s*/g);
  587.         var newSet = [];
  588.         var inserted = false;
  589.         
  590.         for (var i=0; i<set.length; i++){
  591.             newSet.push(set[i]);
  592.             if (insertAfter && set[i] == insertAfter){
  593.                 newSet.push(id);
  594.                 inserted = true;
  595.             }
  596.         }
  597.         
  598.         if (!inserted){
  599.             newSet.push(id);
  600.         }
  601.         newSet = newSet.join(','); 
  602.         navbar.currentSet = newSet;
  603.         navbar.setAttribute('currentset', newSet);
  604.         
  605.         //save the changes
  606.         document.persist("nav-bar","currentset"); 
  607.     }
  608. }
  609.  
  610.  
  611. interclue.initPref = function(name, initValue){
  612.     if (interclue.getPref(name, null) === null){
  613.         interclue.setPref(name, initValue);
  614.         return true;
  615.     }
  616.     else {
  617.         return false;
  618.     }
  619. }
  620.  
  621.  
  622. /**
  623. */
  624. interclue.getPref = function(name, defaultVal){
  625.     try{
  626.         var branch = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
  627.         switch (branch.getPrefType(name)){
  628.             case 32 : //string
  629.                 return  branch.getCharPref(name);
  630.             case 64 : //int
  631.                 return branch.getIntPref(name);
  632.             case 128: //bool
  633.                 return branch.getBoolPref(name);
  634.         }
  635.     
  636.     }catch(e){}
  637.  
  638.     return defaultVal;
  639. }
  640.  
  641. interclue.setPref = function(name, val){
  642.  
  643.     //dont set prefs if we are about to uninstall the add-on
  644.     if (interclue.uninstallOnNextStart){return};
  645.  
  646.     var branch = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
  647.     
  648.     if ((val === true) || (val === false)){
  649.         branch.setBoolPref(name, val);
  650.     }
  651.     else if (typeof val == 'string'){
  652.         branch.setCharPref(name, val);
  653.     }
  654.     else {
  655.         branch.setIntPref(name, val);
  656.     }
  657. }
  658.  
  659.  
  660. interclue.killPref = function(name){
  661.     var branch = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
  662.     branch.deleteBranch(name);
  663. }
  664.  
  665.  
  666. //~ interclue.restart = function(event){
  667.     //~ if (event && event.button == 2){return};
  668.     //~ var startup = Components.interfaces.nsIAppStartup;
  669.     //~ Components.classes["@mozilla.org/toolkit/app-startup;1"].getService(startup).quit(startup.eRestart | startup.eAttemptQuit);
  670. //~ }
  671.  
  672.  
  673. //~ interclue.handleKeyDown = function(evt){
  674.  
  675.     //~ if (!interclue.keydown){
  676.         //~ interclue.keydown = true;
  677.         
  678.         //~ var Klib = interclue.getKlib();
  679.         //~ if (Klib && Klib.User.winLoggedIn){
  680.             //~ Klib.Clue.handleHotKeys(evt);
  681.         //~ }
  682.     //~ }
  683. //~ }
  684.  
  685. //~ interclue.handleKeyUp = function(evt){
  686.     //~ interclue.keydown = false;
  687.     
  688.     //~ var Klib = interclue.getKlib();
  689.     //~ if (Klib && Klib.User.winLoggedIn){
  690.         //~ Klib.Clue.fireHotKeyOff();
  691.     //~ }
  692. //~ }
  693.  
  694. interclue.events = {};
  695.  
  696. interclue.addEvent = function(evtName, func){
  697.     interclue.events[evtName] = interclue.events[evtName] || [];
  698.     interclue.events[evtName].push(func);
  699. }
  700.  
  701. interclue.removeEvent = function(evtName, func){
  702.  
  703.     if (interclue.events[evtName] && interclue.events[evtName].length){
  704.         var evts = [];
  705.         for (var i=0; i<interclue.events[evtName].length; i++){
  706.             if (interclue.events[evtName][i] != func){
  707.                 evts.push(interclue.events[evtName][i]);
  708.             }
  709.         }
  710.         interclue.events[evtName] = evts;
  711.     }
  712. }
  713.  
  714. interclue.fireEvent = function(evtName, args){
  715.     interclue.events[evtName] = interclue.events[evtName] || [];
  716.     for (var i=0; i<interclue.events[evtName].length; i++){
  717.         interclue.events[evtName][i](args);
  718.     }
  719. }
  720.  
  721. //hash table of hints that have already been viewed.
  722. interclue.hintsShown = {};
  723.  
  724. interclue.showHint = function(popupId, ele, imageURL, tutorialPage, x, y){
  725.     //can either be called with showHint(id, ele, [tooltipposition])
  726.     //of showHint(id, x, y, [tooltipposition]) 
  727.     
  728.     //would normally use boxObject to get dimentions but hintBox is collapsed so width & height are 0. 
  729.     var HINT_BOX_WIDTH = 354;
  730.     var HINT_BOX_HEIGHT = 219;
  731.     //perhaps it would be better to check the height and width after the first time it is viewed?
  732.     //maybe make it hidden and but not collapsed, then get the dimentions?
  733.     //for now am cheating
  734.     
  735.     var Klib = interclue.getKlib();
  736.     
  737.     //are we supposed to be showing this hint?
  738.     if (!interclue.hintsShown[popupId] && interclue.getKlib().Pref.get("hint."+ popupId +".show")){
  739.         interclue.hintsShown[popupId] = true;
  740.         
  741.         var popup = document.getElementById('interclue-hint-popup');
  742.         popup.popupId = popupId;
  743.         //set the message title, and text
  744.         document.getElementById('interclue-hint-title').value = Klib.string("hint."+ popupId +".title");
  745.         document.getElementById('interclue-hint-text').firstChild.data = Klib.string("hint."+ popupId +".text");
  746.         document.getElementById('interclue-hint-checkbox-dontshowagain').checked = false;
  747.         document.getElementById('interclue-hint-title-image').src = imageURL ? imageURL : '';
  748.         document.getElementById('interclue-hint-title-image').collapsed = imageURL ? false : true;
  749.         
  750.         var link = document.getElementById('interclue-hint-link');
  751.         if (tutorialPage){    
  752.             link.tutorialPage = tutorialPage; 
  753.             //link.setAttribute("value", Klib.string("hint.link.text"));
  754.             link.collapsed = false;
  755.         }
  756.         else {
  757.             link.collapsed = true;
  758.         }
  759.         //show hint
  760.         var browserBox = document.getElementById('main-window').boxObject;
  761.         
  762.         //position relative to an element?
  763.         if (ele){
  764.             
  765.             //choose the correct location for the popup depending on the elements location relative to the browser window
  766.             var eleBox = ele.ownerDocument.getBoxObjectFor(ele);
  767.             
  768.             x = eleBox.screenX;
  769.             y = eleBox.screenY;
  770.                 
  771.             //use tooltip positioning
  772.             //http://www.bekkoame.ne.jp/~poetlabo/WWW/XULref/common.html
  773.             
  774.             //where popup content should be anchored on the element
  775.             //popupanchor="none | topleft | topright | bottomleft | bottomright" 
  776.             
  777.             //which side of the popup content should be attached to the popupanchor. 
  778.             //popupalign="none | topleft | topright | bottomleft | bottomright" 
  779.             
  780.             
  781.             //popup.showPopup(document.getElementById("interclue-statusbarpanel"), x, y, "popup", popupanchor, popupalign);
  782.         }
  783.         
  784.         //position the hint box.
  785.         var hor = ((x + HINT_BOX_WIDTH) >= (browserBox.screenX + browserBox.width)) ? "right" : "left";
  786.         var ver = ((y + HINT_BOX_HEIGHT) >= (browserBox.screenY + browserBox.height)) ? "bottom" : "top";
  787.         
  788.         //adjust for direction and drop shadow
  789.         if (hor == "right"){
  790.             x -= HINT_BOX_WIDTH;
  791.             x += 10;
  792.         }
  793.         if (ver == "bottom"){
  794.             y -= HINT_BOX_HEIGHT;
  795.             y += 10;
  796.         }
  797.         popup.className = "interclue-hint-"+ ver +"-"+ hor;
  798.         
  799.         //adjust spacers 
  800.         document.getElementById("interclue-hint-popup-spacer-top").setAttribute("height", (ver == "bottom") ? 8 : 37); 
  801.         document.getElementById("interclue-hint-popup-spacer-bottom").setAttribute("height", (ver == "bottom") ? 37 : 8); 
  802.         
  803.         //show the popup
  804.         popup.showPopup(document.getElementById("interclue-statusbarpanel"), x, y, "popup", null, null);
  805.     }
  806. }
  807.  
  808. interclue.closeHint = function(){
  809.  
  810.     var popup = document.getElementById('interclue-hint-popup');
  811.     popup.hidePopup();
  812.     
  813.     if (document.getElementById('interclue-hint-checkbox-dontshowagain').checked){
  814.         var popupId = popup.popupId;
  815.         //and save into prefs.
  816.         interclue.getKlib().Pref.set("hint."+ popupId +".show", false);
  817.     }
  818. }
  819.  
  820. interclue.showTutorialPage = function(page){
  821.     var Klib = interclue.getKlib();
  822.     Klib.Tutorial.showTutorial(page);
  823.     interclue.closeHint();
  824. }
  825.  
  826. /**
  827. * once a day ping the update server.
  828. */
  829. interclue.updatePing = function(){
  830.     
  831.     var Klib = interclue.getKlib();
  832.     
  833.     if (Klib){
  834.         Klib.Update.checkForUpdates();
  835.         //try again tomorrow (in case the user likes to keep firefox running for more than 24 hours at a time).
  836.         interclue.updatePingTimer = setTimeout(interclue.updatePing, 24 * 60 * 60 * 1000);    
  837.     }
  838.     else {
  839.         //Klib not initalized, try again in 5 minutes.
  840.         interclue.updatePingTimer = setTimeout(interclue.updatePing, 5 * 60 * 1000);    
  841.     }
  842. }
  843.  
  844. interclue.enable = function(){
  845.     interclue.call("Klib.ClueBridge.setState('enabled')");
  846. }
  847. interclue.disableDomain = function(){
  848.     interclue.call("Klib.ClueBridge.setState('disabled-for-domain')");
  849. }
  850. interclue.disableUntilRestart = function(){
  851.     interclue.call("Klib.ClueBridge.setState('disabled-until-restart')");
  852. }
  853. interclue.disable = function(){
  854.     interclue.call("Klib.ClueBridge.setState('disabled')");
  855. }
  856.  
  857. /**
  858. * read a value from the registry
  859. */
  860. interclue.getRegistryValue = function(key){
  861.     
  862.     var wrk = Components.classes["@mozilla.org/windows-registry-key;1"].createInstance(Components.interfaces.nsIWindowsRegKey);
  863.     
  864.     //accept slashes and backslashes
  865.     key = key.replace(/[\\\/]+/g, '\\');
  866.     
  867.     //split the key into root/path/node segments
  868.     var m = key.match(/^([^\\]+)\\(.+)\\([^\\]+)$/);
  869.     
  870.     if (m){
  871.         var root = m[1].toUpperCase();
  872.         var path = m[2];
  873.         var node = m[3];
  874.         var rootNode;
  875.         
  876.         switch (root){
  877.             case "HKCR": 
  878.             case "HKEY_CLASSES_ROOT":
  879.                 rootNode = wrk.ROOT_KEY_CLASSES_ROOT;
  880.                 break;
  881.                 
  882.             case "HKCU": 
  883.             case "HKEY_CURRENT_USER":
  884.                 rootNode = wrk.ROOT_KEY_CURRENT_USER;
  885.                 break;
  886.             
  887.             case "HKLM": 
  888.             case "HKEY_LOCAL_MACHINE":
  889.                 rootNode = wrk.ROOT_KEY_LOCAL_MACHINE;
  890.                 break;
  891.             
  892.             default:
  893.                 throw Error("Interclue:registry: Invalid root node ["+ root +"]");
  894.         }
  895.         
  896.         //path needs to have backslashes (\) escaped.
  897.         
  898.         try {
  899.             wrk.open(rootNode, path, wrk.ACCESS_READ);
  900.         }catch(e){
  901.             //Failed, assume key doesn't exist?
  902.             return null;
  903.         }
  904.         
  905.         var val;
  906.         switch (wrk.getValueType(node)) {
  907.             case wrk.TYPE_STRING:
  908.                 val = wrk.readStringValue(node);
  909.                 break;
  910.             case wrk.TYPE_BINARY:
  911.                 val = wrk.readBinaryValue(node);
  912.                 break;
  913.             case wrk.TYPE_INT:
  914.                 val = wrk.readIntValue(node);
  915.                 break;
  916.             case wrk.TYPE_INT64:
  917.                 val = wrk.readInt64Value(node);
  918.                 break;
  919.             default:
  920.                 val = null;
  921.         }
  922.         wrk.close();
  923.         return val;
  924.     }
  925.     else {
  926.         throw Error("Invalid registry path ["+ key +"]");
  927.     }
  928. }
  929.  
  930. /**
  931. * return the current Operating System 
  932. * returns "WINNT" on Windows Vista, XP, 2000, and NT systems
  933. * and returns "Linux" on GNU/Linux
  934. */
  935. interclue.getOS = function(){
  936.     return Components.classes["@mozilla.org/xre/app-info;1"].getService(Components.interfaces.nsIXULRuntime).OS;
  937. }
  938.  
  939. /**
  940. * return TRUE is operating system is Windows based (NT, 2000, XP, Vista)
  941. */
  942. interclue.isWindows = function(){
  943.     return (interclue.getOS() == "WINNT");
  944. }
  945.  
  946. /**
  947. * return TRUE is file exists
  948. */
  949. interclue.fileExists = function(path){
  950.     var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
  951.     file.initWithPath(path);
  952.     return file.exists();
  953. }
  954.  
  955. /**
  956. * creates a temporary file and writes the given data to it
  957. * returns the path to the temporary file
  958. */
  959. interclue.writeTempFile = function(data){
  960.     var file = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties).get("TmpD", Components.interfaces.nsIFile);
  961.     file.append("interclue.tmp");
  962.     file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0666);
  963.     
  964.     // file is nsIFile, data is a string
  965.     var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
  966.     
  967.     // use 0x02 | 0x10 to open file for appending.
  968.     foStream.init(file, 0x02 | 0x08 | 0x20, 0666, 0); 
  969.     // write, create, truncate
  970.     //In a c file operation, we have no need to set file mode with or operation, 
  971.     //directly using "r" or "w" usually.
  972.     foStream.write(data, data.length);
  973.     foStream.close();
  974.  
  975.     return file.path;
  976. }
  977.  
  978.  
  979.  
  980.  
  981. /**
  982. * Executes a command as if it were entered onto the command line
  983. *  @fullPathToExe: string : full path to executable to call (eg "c:\windows\notepad.exe")
  984. *  @args: array : Array of command line arguments to add (eg ["/new",  "--help"])?
  985. */
  986. interclue.exec = function(fullPathToExe, args, waitOnReturn){
  987.     
  988.     var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
  989.     file.initWithPath(fullPathToExe);
  990.  
  991.     var process = Components.classes["@mozilla.org/process/util;1"].createInstance(Components.interfaces.nsIProcess);
  992.     process.init(file);
  993.  
  994.     // Run the process.
  995.     var wait = waitOnReturn ? true : false;
  996.     process.run(wait, args, args.length);
  997. }
  998.  
  999. /**
  1000. */
  1001. interclue.checkIfUpdated = function(){
  1002.     var Klib = interclue.getKlib();
  1003.     
  1004.     if (Klib){
  1005.         Klib.Update.runUpdateScripts();
  1006.     }
  1007.     else {
  1008.         //try again in a moment
  1009.         setTimeout(interclue.checkIfUpdated , 2000)
  1010.     }
  1011. }
  1012.  
  1013. /**
  1014. * return the zoom level of the currently visible (focused) document in FF3
  1015. * returns 0 if zoom level is unavailable (FF < 3)
  1016. */
  1017. interclue.getCurrentDocZoomLevel = function(){
  1018.     var level = getBrowser().mCurrentBrowser.markupDocumentViewer.fullZoom;
  1019.     return (typeof level == "number") ? level : 1;
  1020. }
  1021.  
  1022. /**
  1023. * converts a URL string to a URI that is used in many firefox functions
  1024.  
  1025. == example URI returned from "http://www.mozilla.com/en-US/" ==
  1026.  
  1027. spec=http://www.mozilla.com/en-US/
  1028. prePath=http://www.mozilla.com
  1029. scheme=http
  1030. userPass=
  1031. username=
  1032. password=
  1033. hostPort=www.mozilla.com
  1034. host=www.mozilla.com
  1035. port=-1
  1036. path=/en-US/
  1037. */
  1038.  
  1039. interclue.urlToURI = function(url){
  1040.     try {
  1041.         return Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService).newURI(url, null, null);
  1042.     }catch(e){
  1043.         return null;
  1044.     }
  1045. }
  1046.  
  1047.  
  1048. /**
  1049. * keep track of where the mouse is over our browser
  1050. */
  1051. interclue.Mouse = {};
  1052. interclue.Mouse.screenX = 0;
  1053. interclue.Mouse.screenY = 0;
  1054. interclue.Mouse.init = function(){
  1055.     window.addEventListener("mousemove", interclue.Mouse.onMouseMove, false);
  1056. }
  1057. interclue.Mouse.cleanup = function(){
  1058.     window.removeEventListener("mousemove", interclue.Mouse.onMouseMove, false);
  1059. }
  1060. interclue.Mouse.onMouseMove = function(evt){
  1061.     interclue.Mouse.screenX = evt.screenX;
  1062.     interclue.Mouse.screenY = evt.screenY;
  1063. }
  1064.  
  1065.  
  1066. /**
  1067. * the interclue tooltip
  1068. */
  1069. interclue.Tooltip = {}
  1070. interclue.Tooltip.init = function(){
  1071.     //attach functions to the tooltip object
  1072.     var tooltip = document.getElementById("interclue-tooltip");
  1073.     tooltip.startHideTimer = interclue.Tooltip.startHideTimer;
  1074.     tooltip.stopHideTimer = interclue.Tooltip.stopHideTimer;
  1075. }
  1076. /**
  1077. * starts the hide timer
  1078. */
  1079. interclue.Tooltip.startHideTimer = function(){
  1080.  
  1081.     var tooltip = document.getElementById("interclue-tooltip");
  1082.     var delay = parseInt(tooltip.getAttribute("hidedelay"));
  1083.     tooltip.stopHideTimer();
  1084.     tooltip.hideTimer = setTimeout(function(){
  1085.         tooltip.hidePopup()
  1086.     }, 4000);
  1087. }
  1088. /**
  1089. * stop the hide timer
  1090. * NOTE: this doesn't work in FF2, any attempt to move the mouse over the tooltip will hide it!
  1091. */
  1092. interclue.Tooltip.stopHideTimer = function(){
  1093.     var tooltip = document.getElementById("interclue-tooltip");
  1094.     if (tooltip.hideTimer){
  1095.         clearTimeout(tooltip.hideTimer);
  1096.     }
  1097. }
  1098. /**
  1099. * shows the tooltip
  1100. */
  1101. interclue.Tooltip.show = function(text, screenX, screenY){
  1102.     //set the text of the tooltip
  1103.     var desc = document.getElementById("interclue-tooltip-description");
  1104.     if (desc.firstChild && desc.firstChild.nodeType == 3){
  1105.         desc.firstChild.data = text;
  1106.     }
  1107.     else {
  1108.         var textnode = document.createTextNode(text);
  1109.         desc.appendChild(textnode);
  1110.     }  
  1111.     //and show the tooltip
  1112.     screenX = screenX || interclue.Mouse.screenX;
  1113.     screenY = screenY || interclue.Mouse.screenY;
  1114.     
  1115.     //have to put this in a timer here, 
  1116.     //otherwise the tooltip just doesn't show, dont know why?
  1117.     setTimeout(function(){
  1118.         var tooltip = document.getElementById("interclue-tooltip");
  1119.         tooltip.text = text;
  1120.         if (typeof tooltip.openPopupAtScreen == "function"){
  1121.             tooltip.openPopupAtScreen(screenX, screenY);
  1122.         }
  1123.         //FF2 doesn't support openPopupAtScreen
  1124.         else {
  1125.             //use tooltip positioning
  1126.             //http://www.bekkoame.ne.jp/~poetlabo/WWW/XULref/common.html
  1127.             
  1128.             //where popup content should be anchored on the element
  1129.             //popupanchor="none | topleft | topright | bottomleft | bottomright" 
  1130.             
  1131.             //which side of the popup content should be attached to the popupanchor. 
  1132.             //popupalign="none | topleft | topright | bottomleft | bottomright" 
  1133.             
  1134.             tooltip.showPopup(document.getElementById("main-window"), screenX, screenY, "tooltip", "bottomleft", "bottomleft");
  1135.         }
  1136.     }, 50);   
  1137. }
  1138.  
  1139.  
  1140. interclue.redirects = {};
  1141. interclue.redirects["google"] = function(url){
  1142.     //check for google redirections
  1143.     var m = url.match(/^http:\/\/[^\.]+.google.[^\/]+\/interstitial\?url=([^&]+)/i);
  1144.     return m ? decodeURIComponent(m[1]) : url;
  1145. }
  1146.  
  1147. /**
  1148. * removes known redirects from a url
  1149. */
  1150. interclue.removeRedirects = function(url){
  1151.     //assume each redirect will only occur once
  1152.     for(var id in interclue.redirects){
  1153.         url = interclue.redirects[id](url);
  1154.     }
  1155.     return url;
  1156. }
  1157.  
  1158. /**
  1159. * return TRUE if link points to the same domain as the page it is on.
  1160. */
  1161. interclue.isInternalLink = function(link){
  1162.     var docURI = interclue.urlToURI(link.ownerDocument.URL);
  1163.     var linkURL = interclue.removeRedirects(link.href);
  1164.     var linkURI = interclue.urlToURI(linkURL);
  1165.     
  1166.     return (docURI && linkURI && docURI.host && docURI.scheme && docURI.scheme == linkURI.scheme && docURI.host == linkURI.host);
  1167. }
  1168.  
  1169. /**
  1170. * duh
  1171. */
  1172.  
  1173.  
  1174. window.addEventListener('load', interclue.init, true);
  1175. window.addEventListener('close', interclue.shutdown, true);
  1176.